package org.jiuling.local.tools.convert;

import org.jiuling.local.tools.convert.annotations.Alias;
import org.jiuling.local.tools.exception.LocalToolsException;
import org.jiuling.local.tools.util.AnnotationUtil;
import org.jiuling.local.tools.util.ClassUtil;
import org.jiuling.local.tools.verify.ObjectVerify;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * Map转换工具
 * @author 紫灵
 * @date 2023年02月15日 17时03分09秒
 */
@Deprecated
public class MapConvert {

    /** 私有构造方法，禁止创建对象 */
    private MapConvert(){}

    /**
     * 转为对象
     * @param map 集合
     * @param clazz 类
     * @return 对象
     * @param <T> 泛型对象
     */
    public static <T> T toObject(Map map, Class<T> clazz) throws LocalToolsException {
        try {
            T t = clazz.getDeclaredConstructor().newInstance();
            // 便利属性
            for (Field field : clazz.getDeclaredFields()) {
                Annotation[] annotations = field.getAnnotations();
                Object annotation = AnnotationUtil.getAnnotation(annotations, Alias.class);
                Object fieldName = field.getName();
                if(!ObjectVerify.isNull(annotation)){
                    fieldName = ((Alias) annotation).value();
                }
                Object value = map.get(fieldName);
                if(!ObjectVerify.isNull(value)){
                    // 判断是否为JAVA基础类型
                    if(ObjectVerify.isNull(field.getType().getClassLoader())){
                        ClassUtil.setFieldValue(t,field,value);
                    }else if(value instanceof Map){
                        ClassUtil.setFieldValue(t,field,toObject((Map)value,field.getType()));
                    }
                }
            }
            return t;
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            throw new LocalToolsException(e.getLocalizedMessage());
        }
    }

    /**
     * Map转String
     * @param mapParam map参数
     * @param keyConnector 键值对连接
     * @param paramConnector 参数连接
     * @return String信息
     */
    public static String toString(Map<String,Object> mapParam,String keyConnector,String paramConnector){
        StringBuilder stringBuilder = new StringBuilder();
        // 遍历出map的Key与Value并进行拼接
        // TODO 验证属性是否为基础类型，不为基础类型则再次进行转换
        for (Map.Entry<String,Object> entry :mapParam.entrySet()){
            stringBuilder.append(entry.getKey());
            stringBuilder.append(keyConnector);
            stringBuilder.append(entry.getValue());
            stringBuilder.append(paramConnector);
        }
        stringBuilder.deleteCharAt(stringBuilder.length() -1);
        return stringBuilder.toString();
    }

    /**
     * 对象转Map
     * @param object 对象
     * @return map数据
     */
    public static Map<String,Object> toMap(Object object) throws IntrospectionException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
        Map<String, Object> map = new HashMap<String,Object>();
        Class<?> clazz = object.getClass();
        for (PropertyDescriptor propertyDescriptor : Introspector.getBeanInfo(clazz).getPropertyDescriptors()){
            if(propertyDescriptor.getName().equals("class")){
                continue;
            }

            // 获取方法注解
            if(propertyDescriptor.getReadMethod().isAnnotationPresent(Alias.class)){
                Method method = propertyDescriptor.getReadMethod();
                Alias alias = method.getAnnotation(Alias.class);
                map.put(alias.value(),method.invoke(object));
            }else
                // 获取属性注解
                if (clazz.getDeclaredField(propertyDescriptor.getName()).isAnnotationPresent(Alias.class)){
                    Field field = clazz.getDeclaredField(propertyDescriptor.getName());
                    Alias alias = field.getAnnotation(Alias.class);
                    field.setAccessible(true);
                    map.put(alias.value(),field.get(object));
                }else
                // 直接通过属性获取
                {
                    Field field = clazz.getDeclaredField(propertyDescriptor.getName());
                    field.setAccessible(true);
                    map.put(propertyDescriptor.getName(),field.get(object));
                }
        }
        return map;
    }

}
